<?php
/**
 * 下单与平仓
 * Created by PhpStorm.
 * Author: zzx
 * Date: 2017/4/4
 * Time: 7:01
 */

// 设定编码格式
header("Content-type: text/html; charset=utf-8");

include 'config.php'; // 引入配置文件
include 'mysqli_api.php'; //引入数据库接口文件
include 'redis.php'; // redis连接文件

$my_conn = my_conn(); // 实例化一个数据库连接
$redis = redis_con(); // 实例化一个redis连接

include 'func.php'; // 公共函数
include 'm_table.php';//引入swoole内存表

// 获取web端配置信息
$re = web_conf(redis_con());
if (!$re['status']) {
    die($re['info']);
}

//实例一个http服务
$server = new swoole_http_server('0.0.0.0', 9501);
// 设置参数
$server->set(array(
    'daemonize' => 0, // 守护进程，生产环境设置为true或1
//    'worker_num' => 2, // 本地虚拟机环境使用，测试和生产环境注意注释掉
    'task_worker_num' => 2, // 开2个异步任务进程，一个用于处理mysql，一个用于处理redis
    'pid_file' => __DIR__ . '/orders.php.pid', // server进程PID

));

// 初始化
$server->add_buffer = array(); // 下单缓存
$jid_arr1 = array(); // 系统开发商和运营商的机构ID
global $current;
static $current = array(); // 当期信息
init($jid_arr1);

// 获取当前信息
$res = get_current();
if (! $res) {
    die("\n获取当期信息失败\n");
}


// 实现HTTP服务，下单时，异步请求此服务，保存订单到内存表，执行下单业务逻辑，完成数据持久化
// 用户查看持仓时，异步请求此服务，返回内存表中相应记录
$server->on('Request', function ($request, $response) use ($server) {

    global $table, $gpstr, $uinfo;

    if ($request->server['path_info'] == '/') {
        // 请求来源验证
        $remote_addr = [$gpstr->get('web_servers')['val'], $gpstr->get('data_source')['val'],
            $gpstr->get('web_server')['val'], $gpstr->get('web_server_innet')['val'], '127.0.0.1'];
        if (!in_array($request->server['remote_addr'], $remote_addr)) {
            $response->end(json_encode(['status' => 0, $remote_addr, $request->server['remote_addr']]));
            return;
        }

        // 根据get_type键值执行相应业务逻辑
        $re = json_decode($request->post['re'], true);
        switch ($re['get_type']) {
            // 下单
            case 'insert':
//                 // 并发控制
//                 if (concurrent_ctrl('insert')) {
//                     $response->end(json_encode(['status' => 0, 'info' => '系统繁忙，请稍后再试！']));
//                     break;
//                 }

                // 处理提交的订单
                $re = submit_order($re['data']);
                if ($re['status']) {
                    $odata = array_pop($re); // 取出订单数据，并从返回数组中删除

                    // 添加到下单队列中
                    $server->add_buffer[] = $odata;
                }

                // 返回消息
                $response->end(json_encode($re));
                break;

            # WEB端获取客户持仓信息
            case 'get_user_chicang':
                $temp = array();
                if ($uinfo->exist($re['uid'])) {
                    $order_lis = explode(',', $uinfo->get($re['uid'])['order_lis']);
                    if (!count($order_lis)) {
                        return;
                    }
                    foreach ($order_lis as $key => $value) {
                        # code...
                        if ($table->exist($value)) {
                            $t = $table->get($value);
                            $t['oid'] = $value;
                            $temp[] = $t;
                        }
                    }
                }
                $response->end(json_encode($temp));
                break;

            default:
                # code...
                break;
        }
    }
});


//执行异步任务队列，下单和平仓
$server->on('Task', function ($serv, $task_id, $from_id, $data) {

    global $my_conn, $redis, $config;

    switch ($data['type']) {

        #################### task1，处理mysql
        # 添加持仓
        case 'order_add':
            $t1 = microtime(true);
            order_add($data['data']); // 执行下单业务逻辑
            $t2 = microtime(true);
            //concurrent_ctrl('upspeed', ['t1' => $t1, 't2' => $t2, 'odata' => $data['data'], 'hkey' => 'speed_buy']); // 更新处理速度
            break;

        # 平仓
        case 'order_close':
            $t1 = microtime(true);
            order_close($data['data']); // 执行平仓业务逻辑
            $t2 = microtime(true);
            //concurrent_ctrl('upspeed', ['t1' => $t1, 't2' => $t2, 'odata' => $data['data'], 'hkey' => 'speed_sell']); // 更新处理速度
            break;

        # 处理异常订单
        case 'err_order':
            loading_orders($my_conn); // 处理异常订单
            break;

        # 同步数据库
        case 'sysc':
            sysnc();
            break;

        #################### 以下task2，处理redis
        # 检查web配置
        case 'web_conf':
            $cnf = $redis->get($config['REDIS_PREFIX'] . 'conf_change');
            if ($cnf) {
                $cnf = json_decode($cnf, true);
                if (is_array($cnf)) {
                    web_conf($redis, $cnf);
                }
            }
            break;

        # 更新redis
        case 'up_redis':
            $data = $data['data'];
            up_redis($data['r_data'], $data['r_type']);
            break;
            
        case 'get_current':
            get_current();
            break;
            
        case 'clear_current':
            clear_current($data['data']);
            break;
            
        case 'check_winresult':
            check_winresult($data['data']);
            break;
            
        default:
            # code...
            break;
    }


});


// 异步任务执行回调，如果在task方法中设置了回调函数，Task返回结果时会直接执行指定的回调函数，不再执行此回调
$server->on('Finish', function ($serv, $task_id, $data) {
    //在此执行异步任务中finish方法的回调
    switch ($data['type']) {
        // 更新redis
        case 'up_redis':
            $data = $data['data'];
            $serv->task(array('type' => 'up_redis', 'data' => $data), 1);
            break;

        default:
            break;
    }
});


// work进程启动，处理当前的持仓，和执行下单与平仓
$server->on('WorkerStart', function ($serv, $worker_id) {

    if (!$serv->taskworker) { // 排除taskworker

        $my_conn = my_conn();
        
        
        swoole_timer_tick(1000, function () use ($serv, $worker_id, $my_conn) {

            global $table, $table_price, $gpstr, $gp, $q_table, $current, $config;
            

            // 并发控制
            //concurrent_ctrl('add_buffer', null, $redis);

            // 下单处理
            $data_in = $serv->add_buffer; // 等待处理下单业务逻辑的数据包
            $serv->add_buffer = array(); // 清空下单缓存

//            if ($data_in && $gp->get('is_add')['val']) {
            if ($data_in) {
                // 投递到异步下单进程中
                $serv->task(array('type' => 'order_add', 'data' => $data_in), 0);
            }

           if ($worker_id == 0) {
               $time = time();

               // 平仓
               $data_out = array(); // 已经完成下单，等待处理平仓业务逻辑的数据包
               // 循环持仓队列
               foreach ($q_table as $key => $row) {
                   $q_table->del($key);

                   //添加到待处理数组
                   $row['key'] = $key;
                   $data_out[] = $row;
               }
               // 投递到异步平仓进程中
               if ($data_out) {
               	
               	print_r($data_out);
               	
               	   echo 'start data out' . "\n";
                   $serv->task(array('type' => 'order_close', 'data' => $data_out), 0);
               }

               // 系统停盘后30分钟执行相关业务
               $end_time = $gpstr->get('end_time2')['val'];
               $t = strtotime('+30 min', strtotime(date($end_time)));
               if ($time >= $t) {
                   $serv->task(array('type' => 'err_order'), 0); // 处理异常订单
                   $serv->task(array('type' => 'sysc'), 0); // 同步统计表
                   clear_uorder(); // 清除用户持仓信息
               }

           }

            if ($worker_id == 1) {
                // 此进程用于处理每秒必须完成的任务，对容易被阻塞的异步任务，注意不能在此投递
                $time = time();
                
                //$prev . 'win_queue'
                if($time % 3 == 0){
                    $serv->task(array('type' => 'check_winresult', 'data' => []), 1);
                }
                

                if($time % 5 == 0){
                    $serv->task(array('type' => 'get_current', 'data' => []), 1);
                }
                
                $is_do_ssc = false;
                $is_do_kl8 = false;
                
                $result = [];
                if($time % 4 == 0){
                    $redis = redis_tcon();
                    
                    if($redis->exists($config['REDIS_PREFIX'] . 'datas_win_oqueue') && $redis->lSize($config['REDIS_PREFIX'] . 'datas_win_oqueue') >= 1){
                        $result = $redis->rPop($config['REDIS_PREFIX'] . 'datas_win_oqueue');
                        $result = json_decode($result, true);
                        
                        if($result['type'] == 'kl8'){
                            $is_do_kl8 = true;
                        }else if($result['type'] == 'ssc'){
                            $is_do_ssc = true;
                        }
                    }
                }
                
//                 $current = json_decode($gpstr->get('current')['val'], true);
                
//                 if(isset($current['ssc_openeriod']) && $current['ssc_openeriod'] != ''){
//                     $is_do_ssc = true;
//                 }
                
//                 if(isset($current['kl8_Issue']) && $current['kl8_Issue'] != ''){
//                     $is_do_kl8 = true;
//                 }
                
                
                // 并发控制
//                 concurrent_ctrl('', null, $redis);

                //TODO 平仓
                # 平仓 #########################################################
                // 读取所有商品最新价格
                // 循环持仓队列，取出需要平仓的订单，投到待平仓队列表中
                
                if(($is_do_ssc || $is_do_kl8) && !empty($result)){
                	
                    foreach ($table as $key => $row) {
                        // 跳过可能正好被删除的记录
                        if (!$table->get($key)) {
                            continue;
                        }
                        // 检查当前记录是否可能为空
                        if (!$table->get($key)['uid']) {
                            $table->del($key);
                            continue;
                        }
    
                        // 取出已经到平仓时间的，且不在执行正常平仓中的
                        if ($is_do_ssc && $result['data'][0] == $row['period']) {
                            $table->del($key);
                            
                            $row['ssc_winningNumber'] = $result['data'][1];
                            
                            //添加到待处理队列表
                            $q_table->set($key, $row);
                        }
                        
                        // 取出已经到平仓时间的，且不在执行正常平仓中的
                        if ($is_do_kl8 && $result['data'][0] == $row['period']) {
                            $table->del($key);
                            
                            $row['kl8_WinNumber'] = $result['data'][1];
                            
                            //添加到待处理队列表
                            $q_table->set($key, $row);
                        }
                        
                    }//end foreach
    
                    //do clear 
                    if($is_do_ssc){
                        $serv->task(array('type' => 'clear_current', 'data' => ['clear_type'=>'ssc']), 1);
                    }
                    if($is_do_kl8){
                        $serv->task(array('type' => 'clear_current', 'data' => ['clear_type'=>'kl8']), 1);
                    }
                    
                    
                }//end check do ssc and kl8
                
                // 检查web_conf
                $serv->task(array('type' => 'web_conf'), 1);
            }
        });
    }
});


//启动服务
$server->start();


/**
 * 添加持仓业务逻辑
 * @param $data 下单数据包，1条或多条下单请求数据集合
 */
function order_add($datas)
{
    global $jid_arr1, $my_conn, $table, $gpstr, $gp, $config, $redis, $server;
    $risk_e = $gp->get('risk_e')['val']; // 特别代理风险金额
    $fee = json_decode($gpstr->get('u_service_fee')['val'], true); // 获取佣金比例，后续使用
    $feee = $gp->get('fee')['val']; // 总扣点比例（%）
    $fee_in = $gp->get('fee_in')['val']; // 扣点方式，内扣外扣，0外扣，1内扣

    foreach ($datas as $key => $data) {
        // 获取客户端webcocket标识
        $fd = $data['fd'];

        //数据异常的处理
        if ($data['uid'] == 0) {
            echo "order_add: 无此客户，uid：{$data['uid']}！";
            continue;
        }

        // 查询用户
        $sql = 'select u.uid, u.oid, utel, jid_level1, jid_level2, jid_level3, jid_level4, balance, ifnull(uc.zj_balance, 0) as zj_balance
from zzx_wp_userinfo as u LEFT JOIN zzx_wp_usercash as uc on u.uid=uc.uid where u.uid=' . $data['uid'];
        $mdata = mysqli_query($my_conn, $sql);
        if (!$mdata) {
            // 当MYSQL错误状态码为2006时，尝试重新链接
            $status = false;
            if (mysqli_errno($my_conn) == '2006' && mysql_reconnect_mipan($my_conn)) {
                $mdata = mysqli_query($my_conn, $sql);
                if ($mdata) {
                    $status = true;
                }
            }

            if ($status == false) {
                echo "客户{$data['uid']}查询异常！";
                send_message_to_client(['message' => '用户未找到！', 'fd' => $fd]); // 通知客户端
                mysql_error_log("客户{$data['uid']}查询异常", $sql, $my_conn); // 记录错误日志
                continue;
            }
        }
        $user = mysqli_fetch_assoc($mdata);
        if (!$user) {
            echo "无此客户，uid：{$data['uid']}！";
            continue;
        }

        // 查找所属机构，判断特别代理爆仓与否
        $jid_arr = array_merge($jid_arr1, [$user['jid_level2'], $user['jid_level3'], $user['jid_level4']]);
        $jtype = ['特别代理', '大区代理', '区域代理'];
        for ($i = 2; $i <= 4; $i++) {
            $err = false; // 错误状态
            $sql = 'select id, balance from zzx_jg_company where id=' . $jid_arr[$i];
            $mdata = mysqli_query($my_conn, $sql);
            if (!$mdata) {
                // 机构未找到
                echo $jtype[$i - 2] . $jid_arr[$i] . '未找到！';
                send_message_to_client(['message' => '机构未找到！', 'fd' => $fd]); // 通知客户端
                mysql_error_log("{$jtype[$i-2]}{$jid_arr[$i]}查询异常uid:" . $data['uid'] . ':' . json_encode($user), $sql, $my_conn); // 记录错误日志
                $err = true;
                break;
            }
            $b = mysqli_fetch_assoc($mdata)['balance'] - $risk_e;
            if ($i == 2 && $b < 0) {
                // 特别代理爆仓
                echo $jtype[$i - 2] . $jid_arr[$i] . "余额不足！\n";
                send_message_to_client(['message' => '哎哟，好像代理机构出了点状况，请稍后吧！', 'fd' => $fd]); // 通知客户端
                mysql_error_log("{$jtype[$i-2]}{$jid_arr[$i]}余额不足，uid:" . $data['uid'] . ':' . json_encode($user), $sql, $my_conn); // 记录错误日志
                $err = true;
                break;
            }
        }
        if ($err) {
            continue;
        }

        // 查找上2级用户
        if ($user['oid']) {
            $sql = 'select u.oid from zzx_wp_userinfo as u where u.uid=' . $user['oid'];
            $mdata = mysqli_query($my_conn, $sql);
            if (!$mdata) {
                // 上级用户未找到
                echo '上级用户' . $user['oid'] . '未找到！';
                send_message_to_client(['message' => '上级用户未找到！', 'fd' => $fd]); // 通知客户端
                mysql_error_log("上级用户查询异常uid:" . $user['oid'] . ':' . json_encode($user), $sql, $my_conn); // 记录错误日志
                continue;
            }
            $t = mysqli_fetch_assoc($mdata);
            $fee_u['u_first'] = $user['oid']; // 上级用户
            if ($t['oid']) {
                $fee_u['u_second'] = $t['oid']; // 上2级用户
            }
        }

        // 赠金判断：
        // 1、赠金部分没有扣点。
        // 2、如果客户赢了，扣除赠金后记入用户金豆账户，并从对应机构扣除相应金豆。
        // 3、如果客户输了，对应机构收益应该扣除赠金
        // 如果赠金足够，则使用全部赠金，赠金=订单金额，如果不够，则使用优先使用赠金部分，赠金=赠金账户余额。
        $gift = $user['zj_balance'] - $data['money'] >= 0 ? $data['money'] : $user['zj_balance']; // 赠金金额
        $fee_money = ($data['money'] - $gift) * $feee / 100; // 总返点，赠金订单没有扣点
        $c_fee = $fee_in ? 0 : ($data['money'] - $gift) * $feee / 100; // 如果是内扣，设置客户手续费为0

        # 开启事务 #######################################################################################
        mysqli_query($my_conn, 'BEGIN');
        $rollback = false; // 事务回滚状态

        // 变更用户余额 = 合约金额 + 手续费, 并更新客户总手续费
        $money = $data['money'] + $c_fee;
        $sql = "update zzx_wp_userinfo set balance = balance - $money, service_fee = service_fee - {$c_fee} 
          where uid = {$user['uid']} and balance >= $money";
        $mdata = mysqli_query($my_conn, $sql);
        if (!$mdata || !mysqli_affected_rows($my_conn)) {
            // 用户余额更新错误或余额不足
            echo '用户余额更新错误或余额不足！';
            send_message_to_client(['message' => '账户余额不足！', 'fd' => $fd, 'money' => $user['balance']]); // 通知客户端
            mysql_error_log("更新客户{$user['uid']}金额异常", $sql, $my_conn); // 记录错误日志
            mysqli_query($my_conn, 'ROLLBACK'); // 回滚事务
            $rollback = true;
            continue;
        }

        // 更新赠金余额
        if ($gift > 0) {
            $sql = "update zzx_wp_usercash set zj_balance = zj_balance - $gift where uid = {$user['uid']} and zj_balance >= $gift";
            $mdata = mysqli_query($my_conn, $sql);
            if (!$mdata || !mysqli_affected_rows($my_conn)) {
                // 用户赠金余额更新错误
                echo '用户赠金余额更新错误！';
                send_message_to_client(['message' => '赠金错误！', 'fd' => $fd, 'money' => $user['balance']]); // 通知客户端
                mysql_error_log("更新客户{$user['uid']}赠金余额异常", $sql, $my_conn); // 记录错误日志
                mysqli_query($my_conn, 'ROLLBACK'); // 回滚事务
                $rollback = true;
                continue;
            }
        }

        // 写入持仓订单表
        $code = $data['code'];
        $data['code'] = "'{$data['code']}'"; // 商品编码
        $data['omoney'] = "'{$data['omoney']}'"; // 金额类型
        $data['jid'] = $user['jid_level4']; // 区域代理商
        $data['utel'] = $user['utel']; // 用户号码
        $data['gift'] = $gift; // 赠金
        $data['service_fee'] = $fee_money; // 总返点
        // 删除无效字段，对应表结构
        unset($data['fd']);

        $k = implode(',', array_keys($data));
        $v = implode(',', $data);
        $sql = "insert into zzx_order_position ($k) value ($v)";

        // 写入持仓订单表失败
        if (!mysqli_query($my_conn, $sql)) {
            echo '写入持仓订单表失败';
            send_message_to_client(['message' => '持仓失败！', 'fd' => $fd]); // 通知客户端
            mysql_error_log("客户{$user['uid']}创建订单异常", $sql, $my_conn); // 记录错误日志
            mysqli_query($my_conn, 'ROLLBACK'); // 回滚事务
            $rollback = true;
            continue;
        }

        // 获取持仓订单ID
        $order_id = mysqli_insert_id($my_conn);

        $time = time();
        // 记录客户流水账
        $res = insertFinanceLog_kh($my_conn, $user['jid_level4'], $order_id, -$data['money'], $time, $user['uid'],
            3, '下单流水', -$c_fee, 0, -$gift);
        if (!$res) {
            // 记录客户流水账失败
            echo '记录客户流水账失败';
            send_message_to_client(['message' => '写入流水错误！', 'fd' => $fd]); // 通知客户端
            mysqli_query($my_conn, 'ROLLBACK'); // 回滚事务
            $rollback = true;
            continue;
        }

        // 计算返佣金额
        // 分配佣金, 'dev'=>系统开发商，'third'=>运营中心，'fourth'=>区域代理，'u_first'=>1级用户，'u_second'=>2级用户
        // 系统运营商的返点比例
        $fee['first'] = 100 - $fee['fourth'] - $fee['third'] - $fee['dev'] - $fee['u_first'] - $fee['u_second'];

        foreach ($fee as $k => $v) {

            $err = false; // 错误状态

            if ($k == 'fourth') { // 区域代理
                $jid = $jid_arr[4];
                $money = $fee_money * ($fee[$k] / 100);
            }
            if ($k == 'third') { // 大区代理
                $jid = $jid_arr[3];
                $money = $fee_money * ($fee[$k] / 100);
            }
            if ($k == 'first') { // 系统运营商
                $jid = $jid_arr[1];
                $money = $fee_money * ($fee[$k] / 100);
            }
            if ($k == 'dev') { // 系统开发商
                $jid = $jid_arr[0];
                $money = $fee_money * ($fee[$k] / 100);
            }
            if ($k == 'u_first') { // 1级用户
                $money = $fee_money * ($fee[$k] / 100);
            }
            if ($k == 'u_second') { // 2级用户
                $money = $fee_money * ($fee[$k] / 100);
            }

            if ($money) {
                if ($k != 'u_first' && $k != 'u_second') {

                    // 更新机构金额与总手续费
                    $sql = "update zzx_jg_company set balance=balance+$money,service_fee=service_fee+$money where id={$jid}";
                    if (!mysqli_query($my_conn, $sql) || !mysqli_affected_rows($my_conn)) {
                        echo '更新机构金额与总手续费失败';
                        send_message_to_client(['message' => '更新机构失败！', 'fd' => $fd]); // 通知客户端
                        mysql_error_log("更新区域代理{$jid}金额异常", $sql, $my_conn); // 记录错误日志
                        mysqli_query($my_conn, 'ROLLBACK'); // 回滚事务
                        $rollback = true;
                        $err = true;
                        break;
                    }

                    // 添加机构流水账
                    $res = insertFinanceLog_jg($my_conn, $jid, $order_id, $money, $time, 3, '下单返佣');
                    if (!$res) {
                        echo '添加机构流水账失败';
                        send_message_to_client(['message' => '机构流水错误！', 'fd' => $fd]); // 通知客户端
                        mysqli_query($my_conn, 'ROLLBACK'); // 回滚事务
                        $rollback = true;
                        $err = true;
                        break;
                    }
                } elseif (isset($fee_u[$k])) {
                    // 更新用户分享返点
                    $sql = "update zzx_wp_userinfo set balance = balance + $money where uid = {$fee_u[$k]}";
                    $mdata = mysqli_query($my_conn, $sql);
                    if (!$mdata || !mysqli_affected_rows($my_conn)) {
                        // 用户余额更新错误
                        echo '用户返点更新错误！';
                        send_message_to_client(['message' => '用户返点更新错误！', 'fd' => $fd]); // 通知客户端
                        mysql_error_log("更新客户{$fee_u[$k]}返点金额异常", $sql, $my_conn); // 记录错误日志
                        mysqli_query($my_conn, 'ROLLBACK'); // 回滚事务
                        $rollback = true;
                        $err = true;
                        break;
                    }

                    // 添加用户分享返点流水
                    $res = insertFinanceLog_kh($my_conn, 0, $order_id, $money, $time, $fee_u[$k],
                        8, '分享返点流水', 0, 0, 0);
                    if (!$res) {
                        // 记录客户流水账失败
                        echo '添加用户分享返点流水失败';
                        send_message_to_client(['message' => '写入流水错误！', 'fd' => $fd]); // 通知客户端
                        mysqli_query($my_conn, 'ROLLBACK'); // 回滚事务
                        $rollback = true;
                        $err = true;
                        break;
                    }
                }
            }
        }
        if ($err) {
            continue;
        }
        mysqli_query($my_conn, 'COMMIT'); // 提交事务
        mysqli_query($my_conn, 'END'); // 结束事务
        # 结束事务 ############################################################################################

        if (!$rollback) {
            // 更新redis客户余额
            $sql = 'select balance from zzx_wp_userinfo where uid=' . $user['uid'];
            $money = mysqli_fetch_assoc(mysqli_query($my_conn, $sql))['balance'];

            $data['r_type'] = 'hSet';
            $data['r_data']['key'] = $config['REDIS_PREFIX'] . 'user_' . $user['uid'];
            $data['r_data']['hkey'] = 'balance';
            $data['r_data']['val'] = $money;
            $f_data['type'] = 'up_redis';
            $f_data['data'] = $data;
            $server->finish($f_data);

            // 添加到持仓缓存队列表
            $data['code'] = $code; // 商品编码
            $data['fd'] = $fd; // 商品编码
            $table->set($order_id, $data);

            // 通知客户端
            send_message_to_client(['message' => '订单处理成功！', 'fd' => $fd, 'money' => $money], 1);

            // 更新用户订单信息
            $data['oid'] = $order_id;
            up_uinfo($data);
            
            //获胜投送到获胜队列。
            $redis->lPush($config['REDIS_PREFIX'] . 'trans_bet', json_encode([
                'uid'=>$data['uid'],
                'utel'=>$data['utel'],
                'amount'=>$data['money']
            ]));
            if($redis->lSize($config['REDIS_PREFIX'] . 'trans_bet') > 50){
                $redis->rPop($config['REDIS_PREFIX'] . 'trans_bet');
            }
        }
    }
}


/**
 * 异步平仓，执行平仓的业务逻辑和数据的持久化
 * @param $data 异步任务数据包
 */
function order_close($data)
{
    global $my_conn, $q_table, $gp, $err_orders, $config, $redis, $server, $gpstr;
    $jg_bc_price = $gp->get('risk')['val']; // 区域代理爆仓金额
    $fee_in = $gp->get('fee_in')['val']; // 扣点方式，内扣外扣，0外扣，1内扣

    //循环订单列表，逐条执行平仓
    foreach ($data as $key => $re) {

        $fd = $re['fd']; // 客户端webcocket标识
        unset($re['fd']);// 删除客户端webcocket标识
        $jid = null;//每个循环 机构ID要清零
        //$fee = $fee_in ? $re['service_fee'] : 0; // 机构手续费，内扣时由机构承担
        $fee = 0; // 机构手续费，内扣时由机构承担
        $time = time(); // 操作时间统一用平仓时间
        $re['oid'] = $re['key']; // 订单oid

        // 判断买涨/买跌，0涨1跌，和盈亏，相对于客户
        
        //判断单双
        //判断中奖号
        
        /**
         * $row['ssc_winningNumber'];
         * $row['kl8_WinNumber'];
         */
        $is_ssc = false;
        $is_kl8 = false;
        if(isset($re['kl8_WinNumber']) && !empty($re['kl8_WinNumber'])){
            $is_kl8 = true;
        }
        if(isset($re['ssc_winningNumber']) && !empty($re['ssc_winningNumber'])){
            $is_ssc = true;
        }
        
        if(!$is_ssc && !$is_kl8){
        	continue;
        }
        
        $dc = 0;
        
        //$re  订单类型，单双 otype 0single 1 double
        if($is_kl8){
            list($num_str, $num_af) = explode('+', $re['kl8_WinNumber']);
            $win_nums = explode(' ', $num_str);
            $win_nums[2] = intval($win_nums[2]);
            
            if ($re['otype'] == 0) {
                if($win_nums[2] % 2 == 1){
                    $dc = 1;
                }else{
                    $dc = 0;
                }
            } else {
                if($win_nums[2] % 2 == 1){
                    $dc = 0;
                }else{
                    $dc = 1;
                }
            }
        }
        
        if($is_ssc){
            $win_nums = explode(' ', $re['ssc_winningNumber']);
            $win_nums[4] = intval($win_nums[4]);
            if ($re['otype'] == 0) {
                if($win_nums[4] % 2 == 1){
                    $dc = 1;
                }else{
                    $dc = 0;
                }
            } else {
                if($win_nums[4] % 2 == 1){
                    $dc = 0;
                }else{
                    $dc = 1;
                }
            }
        }
        
        
        $jg_money = null;
        $setval = null;
        
        $re['omoney'] = str_replace("'", '', $re['omoney']); // 订单金额类型
        
        //dc > 0 win, dc = 0 fail
        if($dc > 0){
            // 盈，赢
            $money = $re['omoney'];
            $money = explode('_', $gpstr->get($money)['val']); // 转换订单金额和收益，0金额，1收益
            $lots = $re['lots']; // 手数
            
            $c_money = $money[1] * $lots;//客户盈金额
            $ploss = $money[1] * $lots - $money[0] * $lots;
            $jg_money = -$ploss; // 机构亏金额
            $setval = "balance=balance+$c_money, gains=gains+{$ploss}"; // 更新客户余额 ,更新盈利sql
        }else {
            // do nothing
        }
        
        # 开启事务 #######################################################################################
        mysqli_query($my_conn, 'BEGIN');
        $rollback = false; // 事务回滚状态

        // 更新机构金额、添加机构流水账，内扣时，手续费由机构承担
        if ($jg_money) { // 客户输或赢，且排除赠金
            // 更新机构金额
            $res = updateMoney_jg($my_conn, $jg_money - $fee, $re['jid'], $jg_bc_price, $re['uid']);
            if (!$res) {
                mysqli_query($my_conn, 'ROLLBACK'); // 回滚事务
                $rollback = true;
                send_message_to_client(['message' => '更新机构失败！', 'fd' => $fd]); // 通知客户端
                continue;
            }
            $jid = $res;//保存被操作的机构ID，爆仓时为特别会员ID，正常下为会员单位ID

            //更新下单机构ID
            updateFinanceLog_kh($my_conn, $jid, $re['oid']);

            // 添加机构流水账
            $res = insertFinanceLog_jg($my_conn, $jid, $re['oid'], $jg_money - $fee, $time, 4, '订单平仓');
            if (!$res) {
                mysqli_query($my_conn, 'ROLLBACK'); // 回滚事务
                $rollback = true;
                send_message_to_client(['message' => '机构流水错误！', 'fd' => $fd]); // 通知客户端
                continue;
            }
        }

        // 更新客户金额、盈利金额、亏损金额
        if ($setval) {
            $sql = "update zzx_wp_userinfo set $setval where uid={$re['uid']}";
            $res = mysqli_query($my_conn, $sql);
            if (!$res || !mysqli_affected_rows($my_conn)) {
                $status = false;
                // 当MYSQL错误状态码为2006时，尝试重新链接
                if (mysqli_errno($my_conn) == '2006' && mysql_reconnect_mipan($my_conn)) {
                    $sql = "update zzx_wp_userinfo set $setval where uid={$re['uid']}";
                    $res = mysqli_query($my_conn, $sql);
                    if ($res && mysqli_affected_rows($my_conn)) {
                        $status = true;
                    }
                }

                if ($status == false) {
                    echo '更新客户金额异常' . $sql . "\n";
                    mysql_error_log("更新客户{$re['uid']}金额异常", $sql, $my_conn); // 记录错误日志
                    mysqli_query($my_conn, 'ROLLBACK'); // 回滚事务
                    $rollback = true;
                    send_message_to_client(['message' => '更新客户异常！', 'fd' => $fd]); // 通知客户端
                    continue;
                }
            }
        }

        // 添加客户流水账
        if ($dc > 0 && $fee_in == 0) { // 外扣，盈利或平，内扣，赢
            if (!isset($jid)) {
                $jid = $re['jid']; // 与其交易的机构会员单位或特别会员ID，外扣平单时记录会员ID
            }
            $res = insertFinanceLog_kh($my_conn, $jid, $re['oid'], $c_money, $time, $re['uid'], 4,
                '平仓收入', 0, $dc ? 1 : 0, $re['gift']);
            if (!$res) {
                mysqli_query($my_conn, 'ROLLBACK'); // 回滚事务
                $rollback = true;
                send_message_to_client(['message' => '客户流水异常！', 'fd' => $fd]); // 通知客户端
                continue;
            }
        }


        // 写入历史订单信息表
        // 删除无效数据，以对应mysql数据结构
        unset($re['key']);
        
        /**
         * kl8_WinNumber
         * ssc_winningNumber
         */
        if(isset($re['kl8_WinNumber'])){
            unset($re['kl8_WinNumber']);
        }
        if(isset($re['ssc_winningNumber'])){
            unset($re['ssc_winningNumber']);
        }

        $re['code'] = "'{$re['code']}'";// 设置商品CODE，以对应mysql数据结构
        $re['member_id'] = isset($jid) ? $jid : $re['jid']; // 与交易的机构ID，没有交易时，为会员单位的ID
        $re['omoney'] = "'{$re['omoney']}'";//

        unset($re['jid']);
        
        if($dc == 0){
            $re['revenue'] = 0;
        }
        
        $k = implode(',', array_keys($re));
        $v = implode(',', $re);
        $sql = "insert into zzx_order_history ($k) value ($v)";
        $res = mysqli_query($my_conn, $sql);
        if (!$res) {
            $status = false;
            // 当MYSQL错误状态码为2006时，尝试重新链接
            if (mysqli_errno($my_conn) == '2006' && mysql_reconnect_mipan($my_conn)) {
                $sql = "update zzx_wp_userinfo set $setval where uid={$re['uid']}";
                $res = mysqli_query($my_conn, $sql);
                if ($res && mysqli_affected_rows($my_conn)) {
                    $status = true;
                }
            }
            if ($status == false) {
                echo '创建历史订单异常' . $sql . "\n";
                mysql_error_log("创建历史订单异常", $sql, $my_conn); // 记录错误日志
                mysqli_query($my_conn, 'ROLLBACK'); // 回滚事务
                $rollback = true;
                send_message_to_client(['message' => '平仓失败！', 'fd' => $fd]); // 通知客户端
                continue;
            }
        }

        // 删除持仓信息表
        $sql = 'delete from zzx_order_position where oid=' . $re['oid'];
        $res = mysqli_query($my_conn, $sql);
        if (!$res) {
            echo '删除持仓订单异常' . $sql . "\n";
            mysql_error_log("删除持仓订单异常", $sql, $my_conn); // 记录错误日志
            mysqli_query($my_conn, 'ROLLBACK'); // 回滚事务
            $rollback = true;
            send_message_to_client(['message' => '删除持仓失败！', 'fd' => $fd]); // 通知客户端
            continue;
        }

        mysqli_query($my_conn, 'COMMIT'); // 提交事务
        mysqli_query($my_conn, 'END'); // 结束事务
        # 结束事务 ############################################################################################

        // 处理成功
        if (!$rollback) {
            // 更新redis客户余额
            $sql = 'select balance from zzx_wp_userinfo where uid=' . $re['uid'];
            $money = mysqli_fetch_assoc(mysqli_query($my_conn, $sql))['balance'];

            $data['r_type'] = 'hSet';
            $data['r_data']['key'] = $config['REDIS_PREFIX'] . 'user_' . $re['uid'];
            $data['r_data']['hkey'] = 'balance';
            $data['r_data']['val'] = $money;
            $f_data['type'] = 'up_redis';
            $f_data['data'] = $data;
            $server->finish($f_data);

            // 通知客户端
            send_message_to_client(['message' => '订单处理成功！', 'fd' => $fd, 'money' => $money], 1);

            // 更新用户订单信息
            up_uinfo($re, 1);
            
            //获胜投送到获胜队列。 
            if($dc > 0){
                $redis->lPush($config['REDIS_PREFIX'] . 'trans_success', json_encode([
                    'uid'=>$re['uid'],
                    'utel'=>$re['utel'],
                    'amount'=>$c_money
                ]));
                if($redis->lSize($config['REDIS_PREFIX'] . 'trans_success') > 100){
                    $redis->rPop($config['REDIS_PREFIX'] . 'trans_success');
                }
            }
        }
    }
}


/**
 * 更新机构金额，平仓使用
 * @param $my_conn 数据库连接实例
 * @param $ploss 盈亏金额
 * @param $jid_level4 机构区域代理id
 * @param $jg_bc_price 爆仓金额
 * @param $uid 客户ID
 * @return bool|number 被操作的机构ID,失败时返回false
 */
function updateMoney_jg($my_conn, $money, $jid_level4, $jg_bc_price, $uid)
{
    //更新会员
    $sql = "update zzx_jg_company set balance=balance+$money,gain_loss=gain_loss+$money where id=$jid_level4 and balance>=$jg_bc_price";
    $res = mysqli_query($my_conn, $sql);
    if (!$res) {
        $status = false;
        if (mysqli_errno($my_conn) == '2006' && mysql_reconnect_mipan($my_conn)) {
            $sql = "update zzx_jg_company set balance=balance+$money,gain_loss=gain_loss+$money where id=$jid_level4 and balance>=$jg_bc_price";
            $res = mysqli_query($my_conn, $sql);

            if ($res) {
                $status = true;
            }
        }

        if ($status == false) {
            echo '更新机构金额异常' . "\n";
            mysql_error_log("更新机构{$jid_level4}金额异常", $sql, $my_conn); // 记录错误日志
            return false;
        }
    }

    //如果返回影响记录条数正确，返回会员ID，否则，说明该机构爆仓了
    if (mysqli_affected_rows($my_conn)) {
        return $jid_level4;
    }

    //机构爆仓
    //获取特别服务商ID
    $sql = "select jid_level2 from zzx_wp_userinfo where uid=" . $uid;
    $res = mysqli_query($my_conn, $sql);
    if (!$res) {
        echo "获取客户{$uid}所属特别服务商异常 \n";
        mysql_error_log("获取客户{$uid}所属特别服务商异常", $sql, $my_conn); // 记录错误日志
        return false;
    }

    //特别服务商ID
    $tid = mysqli_fetch_assoc($res)['jid_level2'];
    if (empty($tid)) {
        echo "获取客户{$uid}所属特别服务商异常2 \n";
        mysql_error_log("获取客户{$uid}所属特别服务商异常2", $sql, $my_conn); // 记录错误日志
        return false;
    }

    //更新特别服务商
    $sql = "update zzx_jg_company set balance=balance+$money,gain_loss=gain_loss+$money where id=$tid";
    $res = mysqli_query($my_conn, $sql);
    if (!$res) {
        echo "更新机构{$tid}金额异常 \n";
        mysql_error_log("更新机构{$tid}金额异常", $sql, $my_conn); // 记录错误日志
        return false;
    }
    //如果返回影响记录条数正确，返回特别服务商ID
    if (mysqli_affected_rows($my_conn)) {
        return $tid;
    } else {
        echo "更新机构{$tid}金额异常2 \n";
        mysql_error_log("更新机构{$tid}金额异常2", $sql, $my_conn); // 记录错误日志
    }
}


/**
 * 添加机构流水账
 * @param $my_conn 数据库连接实例
 * @param $jid 机构ID
 * @param $oid 关联表ID
 * @param $money 操作金额
 * @param $time 操作时间
 * @param $dealtype 操作类型, 3表示下单，4表示平仓返现
 * @param $msg 说明
 * @return bool 返回
 */
function insertFinanceLog_jg($my_conn, $jid, $oid, $money, $time, $dealtype, $msg)
{
    // 添加机构流水账
    $sql = "select balance from zzx_jg_company where id=" . $jid;
    $res = mysqli_query($my_conn, $sql);
    if (!$res) {
        return false;
    }

    $insert['afteratm'] = mysqli_fetch_assoc($res)['balance'];
    $insert['jid'] = $jid; // 机构ID
    $insert['dealtype'] = $dealtype; // 操作类型，4表示平仓返现，5表示客户下单返佣
    $insert['linkid'] = $oid; // 关联表ID
    $insert['atm'] = $money; // 操作金额
    $insert['proce'] = 0; // 手续费
    $insert['msg'] = "'$msg'"; // 操作描述
    $insert['createtime'] = $time; // 操作时间

    $k = implode(',', array_keys($insert));
    $v = implode(',', $insert);

    $sql = "insert into zzx_balanceinfo_jg ($k) value ($v)";
    $res = mysqli_query($my_conn, $sql);
    if (!$res) {
        echo '添加机构流水账异常' . "\n";
        mysql_error_log("机构{$jid}添加流水账异常", $sql, $my_conn); // 记录错误日志
        return false;
    }
    return true;
}


/**
 * 在更新机构金额的时候，同时更新下单客户流水的机构ID
 * 更新客户流水账的机构ID
 * @param obj $my_conn
 * @param int $jid
 * @param int $oid
 * @return boolean
 */
function updateFinanceLog_kh($my_conn, $jid, $oid)
{
    $sql = "update zzx_balanceinfo_kh set jigou_id=" . $jid . " where linkid=" . $oid;
    $res = mysqli_query($my_conn, $sql);
    if (!$res) {
        echo '更新客户流水账的机构ID异常' . "\n";
        mysql_error_log("更新客户流水账机构ID{$jid}异常", $sql, $my_conn); // 记录错误日志
        return false;
    }
    return true;
}


/**
 * 添加客户流水
 * @param $my_conn 数据库连接实例
 * @param $jid 机构ID
 * @param $oid 关联表ID
 * @param $money 操作金额
 * @param $time 操作时间
 * @param $uid 客户ID
 * @param $dealtype 操作类型, 3表示下单，4表示平仓返现
 * @param $msg 说明
 * @param $service_fee 手续费
 * @param $dc 下注与开奖的点差，用于判断输赢，根据游戏规则
 * @param $gift 赠金
 * @return bool 返回
 */
function insertFinanceLog_kh($my_conn, $jid, $oid, $money, $time, $uid, $dealtype, $msg, $service_fee, $dc = 0, $gift = 0)
{
    // 添加客户流水账
    $sql = "select balance from zzx_wp_userinfo where uid=" . $uid;
    $res = mysqli_query($my_conn, $sql);
    if (!$res) {
        return false;
    }

    $insert['afteratm'] = mysqli_fetch_assoc($res)['balance'];
    $insert['uid'] = $uid;
    $insert['jigou_id'] = $jid; // 机构ID
    $insert['dealtype'] = $dealtype; // 操作类型, 3表示下单，4表示平仓返现
    $insert['linkid'] = $oid; // 关联表ID
    $insert['atm'] = $money; // 操作金额
    $insert['proce'] = $service_fee; // 手续费
    $insert['msg'] = "'$msg'"; // 操作描述
    $insert['createtime'] = $time; // 操作时间
    $insert['status'] = $dc; // 开奖点差
    $insert['gift'] = $gift; // 赠金

    $k = implode(',', array_keys($insert));
    $v = implode(',', $insert);

    $sql = "insert into zzx_balanceinfo_kh ($k) value ($v)";
    $res = mysqli_query($my_conn, $sql);
    if (!$res) {
        echo '添加客户流水账异常' . $sql . "\n";
        mysql_error_log("客户{$uid}添加流水账异常", $sql, $my_conn); // 记录错误日志
        return false;
    }
    return true;
}


/**
 * 订单提交
 * @param $data 订单数据包
 * @return array
 */
function submit_order($data)
{
    global $gp, $gpstr, $uinfo;

    $current = json_decode($gpstr->get('current')['val'], true);
    
    // 获取请求参数
    $uid = intval($data['uid']); // 客户ID
    $code = $data['pcode']; // 商品标识CODE
    $otype = $data['otype']; // 订单类型，单双
    $omoney = $data['omoney']; // 订单金额类型
    $money = explode('_', $gpstr->get($omoney)['val']); // 转换订单金额和收益，0金额，1收益
    $lots = $data['lots']; // 手数

    // websocket标识
    if (isset($data['fd'])) {
        $fd = $data['fd'];
    } else {
        $fd = 0;
    }
    unset($data); // 删除传入数据

    // 获取web端配置信息
    $urgent = $gp->get('urgent')['val']; // 紧急停盘
    $closed = $gpstr->get('closed')['val']; // 人工停盘
    $interval = $gp->get('interval')['val']; // 操作间隔，防止攻击
    $interval = $interval ? $interval : 10; // 操作间隔默认10秒

    // 用户数据
    $last_time = $uinfo->get($uid)['last_time']; // 最近操作时间

    if ($uid <= 0) {
        return ['status' => 0, 'info' => '登录已过期！'];
    }
    if (!$code) {
        return ['status' => 0, 'info' => '缺少商品标识！'];
    }

    // 设置操作时间
    $time = time();

    // 最近操作时间，防止攻击
    $uinfo->set($uid, ['last_time' => $time]);

    // 判断交易时间
    $re = check_time($time);
    if ($re) {
        return $re;
    }
    // 判断人工停盘
    if ($closed) {
        return ['status' => 0, 'info' => '系统维护中...'];
    }
    // 判断紧急停盘
    if ($urgent) {
        return ['status' => 0, 'info' => $urgent];
    }
    // 操作间隔
    if ($time - $last_time < $interval) {
        return ['status' => 0, 'info' => '操作过于频繁！'];
    }

    # 判断单双类型
    if (!in_array($otype, [0, 1])) {
        return ['status' => 0, 'info' => '订单类型有误！'];
    }
    // 判断订单金额
    if (!$gpstr->exist($omoney)) {
        return ['status' => 0, 'info' => '订单金额有误！'];
    }
    # 判断商品CODE
    if (! in_array($code, ['ssc', 'kl8'])) {
        return ['status' => 0, 'info' => '商品标识有误！'];
    }

    // 设置订单
    $data['fd'] = $fd; // websocket标识
    $data['uid'] = $uid; // 客户ID
    $data['code'] = $code; // 商品CODE
    $data['period'] = $current[$code]; // 当期彩票编号
    $data['buytime'] = $time; // 下单时间
    $data['otype'] = $otype; // 订单单双类型
    $data['lots'] = $lots; // 购买手数
    $data['omoney'] = (string)$omoney; // 订单金额类型
    $data['money'] = $money[0] * $lots; // 订单金额
    $data['revenue'] = $money[1] * $lots; // 预计收益

    return ['status' => 1, 'info' => '提交处理中...', 'data' => $data];
}


/**
 * 载入持仓订单
 * @param $my_conn
 */
function loading_orders($my_conn)
{
    global $gp, $table, $redis;
    $time = time();
    $fee_in = $gp->get('fee_in')['val']; // 手续费内扣外扣，0外扣，1内扣

    // 获取所有持仓订单
    $sql = 'select * from zzx_order_position';
    $orders = mysqli_query($my_conn, $sql);
    if (!$orders) {
        // 当MYSQL错误状态码为2006时，尝试重新链接
        $status = false;
        if (mysqli_errno($my_conn) == '2006' && mysql_reconnect_mipan($my_conn)) {
            $sql = 'select * from zzx_order_position';
            $orders = mysqli_query($my_conn, $sql);

            if ($orders) {
                $status = true;
            }
        }

        if ($status == false) {
            mysql_error_log("执行持仓异常订单处理异常", $sql, $my_conn); // 记录错误日志
            return;
        }
    }

    while ($order = mysqli_fetch_assoc($orders)) {
        //if ($order['selltime'] > $time) {
            if (true) {
            // 添加到持仓队列内存表
            $table->set($order['oid'], $order);
            unset($data);

            // 更新用户订单信息
            up_uinfo($order);

        } else {
            // 异常订单处理

            // 获取当前订单手续费分配记录
            $sql = 'select * from zzx_balanceinfo_jg where dealtype=3 and linkid=' . $order['oid'];
            $worters = mysqli_query($my_conn, $sql);

            // 定义总手续费与状态
            $service_fee = 0;
            $status = true;

            # 开启事务 #######################################################################################
            mysqli_query($my_conn, 'BEGIN');

            while ($water = mysqli_fetch_assoc($worters)) {
                // 更新机构金额与总手续费
                $sql = "update zzx_jg_company set balance=balance-{$water['atm']},service_fee=service_fee-{$water['atm']} where id={$water['jid']}";
                if (!mysqli_query($my_conn, $sql) || !mysqli_affected_rows($my_conn)) {
                    // 更新机构金额与总手续费失败
                    echo '更新机构金额与总手续费失败！';
                    $status = false;
                    mysql_error_log("更新机构{$water['jid']}金额异常", $sql, $my_conn); // 记录错误日志
                    break;
                }

                // 添加机构流水账
                $res = insertFinanceLog_jg($my_conn, $water['jid'], $order['oid'], -$water['atm'], $time, 5, '持仓订单异常，返回客户手续费');
                if (!$res) {
                    // 添加机构流水账失败
                    $status = false;
                    break;
                }

                // 统计手续费
                $service_fee += $water['atm'];
            }

            if (!$status || bccomp($service_fee, $order['service_fee'], 4)) {
                $err_str = "持仓订单{$order['oid']}手续费分配异常，status：{$status}，service_fee：{$service_fee}，order['service_fee']：{$order['service_fee']}";
                echo $err_str . "\n";
                order_error_log($err_str); // 记录错误日志
                mysqli_rollback($my_conn); //回滚事务
                continue;
            }

            // 更新客户金额和总手续费
            $fee = $fee_in ? 0 : $order['service_fee']; // 如果手续费为内扣，设置客户手续费为0
            $money = $order['money'] + $fee;
            $sql = "update zzx_wp_userinfo set balance=balance+$money, service_fee=service_fee+{$fee} where uid={$order['uid']}";
            if (!mysqli_query($my_conn, $sql) || !mysqli_affected_rows($my_conn)) {
                // 更新客户金额与总手续费失败
                echo '更新客户金额与总手续费失败！';
                mysqli_rollback($my_conn); //回滚事务
                mysql_error_log("更新客户金额异常，uid：{$order['uid']}", $sql, $my_conn); // 记录错误日志
                continue;
            }

            // 退回赠金
            if ($order['gift'] > 0) {
                $sql = "update zzx_wp_usercash set zj_balance=zj_balance+{$order['gift']} where uid={$order['uid']}";
                if (!mysqli_query($my_conn, $sql) || !mysqli_affected_rows($my_conn)) {
                    // 更新客户金额与总手续费失败
                    echo '更新客户赠金失败！';
                    mysqli_rollback($my_conn); //回滚事务
                    mysql_error_log("更新客户赠金异常，uid：{$order['uid']}", $sql, $my_conn); // 记录错误日志
                    continue;
                }
            }

            // 添加客户流水账
            $res = insertFinanceLog_kh($my_conn, $order['member_id'], $order['oid'], $order['money'], $time, $order['uid'],
                5, '持仓订单异常，返佣客户合约金额与手续费', $fee, 0, $order['gift']);
            if (!$res) {
                mysqli_query($my_conn, 'ROLLBACK'); // 回滚事务
                continue;
            }


            // 添加异常订单
            $order['code'] = "'{$order['code']}'";
            $k = implode(',', array_keys($order));
            $v = implode(',', $order);
            $sql = "insert into zzx_order_error ($k) value ($v)";
            if (!mysqli_query($my_conn, $sql)) {
                // 添加异常订单失败
                echo '：添加异常订单失败！';
                mysqli_rollback($my_conn); //回滚事务
                mysql_error_log("创建异常订单异常", $sql, $my_conn); // 记录错误日志
                continue;
            }

            // 删除异常持仓订单
            $sql = 'delete from zzx_order_position where oid=' . $order['oid'];
            if (!mysqli_query($my_conn, $sql) || !mysqli_affected_rows($my_conn)) {
                // 删除异常持仓订单失败
                echo '：删除异常持仓订单失败！';
                mysqli_rollback($my_conn); //回滚事务
                mysql_error_log("删除持仓订单异常", $sql, $my_conn); // 记录错误日志
                continue;
            }

            mysqli_query($my_conn, 'COMMIT'); // 提交事务
            mysqli_query($my_conn, 'END'); // 结束事务
            # 结束事务 ############################################################################################
        }
    }
}


/**
 * 更新用户订单信息
 * @param $odata 订单数据
 * @param int $type 0为下单，1为平仓
 */
function up_uinfo($odata, $type = 0)
{
    global $uinfo;

    // 更新redis用户订单信息
    $olis_str = $uinfo->get($odata['uid'])['order_lis']; // 订单oid列表
    if ($olis_str) {

        // 更新
        if ($type) { // 平仓
            $uinfo->decr($odata['uid'], 'all_position', 1); // 最大持仓订单
            $uinfo->decr($odata['uid'], 'all_position', $odata['money']); // 持仓金额
        } else {
            $uinfo->incr($odata['uid'], 'all_position', 1); // 最大持仓订单
            $uinfo->incr($odata['uid'], 'all_position', $odata['money']); // 持仓金额
        }

        if ($type) { // 平仓
            $order_lis = explode(',', $olis_str);
            $tkey = array_search($odata['oid'], $order_lis);
            if ($tkey >= 0) {
                array_splice($order_lis, $tkey, 1);
            }
            $uinfo->set($odata['uid'],['order_lis' => implode(',', $order_lis)]); // 订单oid列表

        } else { // 下单
            $olis_str = $olis_str . ",{$odata['oid']}"; // 订单oid列表
            $uinfo->set($odata['uid'],['order_lis' => $olis_str]); // 订单oid列表
        }

    } else if (!$type) { // 下单

        // 初始化
        $uinfo->set($odata['uid'],['all_position' => 1, 'all_money' => $odata['money'], 'order_lis' => $odata['oid']]);
    }

}

/**
 * 系统初始化
 * @param $jid_arr1 各级机构id
 */
function init(&$jid_arr1)
{
    global $my_conn, $config;
    // 系统开发商id
    $sql = 'select id from zzx_jg_company where jg_type=999'; // 系统开发商
    $mdata = mysqli_query($my_conn, $sql);
    if (!$mdata) {
        die('系统开发商未找到！');
    }
    $jid_arr1[0] = mysqli_fetch_assoc($mdata)['id'];

    // 系统运营商id
    $sql = 'select id from zzx_jg_company where jg_type=1'; // 系统运营商
    $mdata = mysqli_query($my_conn, $sql);
    if (!$mdata) {
        die('系统运营商未找到！');
    }
    $jid_arr1[1] = mysqli_fetch_assoc($mdata)['id'];


    // 修改持仓表自增键，数据库重启后，或自增键异常时，必须重启订单服务程序
    // 历史订单表最大主键值
    $sql = 'select max(oid) AS oid from zzx_order_history';
    $res = mysqli_query($my_conn, $sql);
    $max_oid = mysqli_fetch_array($res, MYSQLI_ASSOC)['oid'];

    // 异常订单表最大主键值
    $sql = 'select max(oid) AS oid from zzx_order_error';
    $res = mysqli_query($my_conn, $sql);
    $max_oid2 = mysqli_fetch_array($res, MYSQLI_ASSOC)['oid'];
    $max_oid = $max_oid2 > $max_oid ? $max_oid2 + 1 : $max_oid + 1;

    // 设置持仓表自增键，注意数据库用户要有此权限
    $sql = "alter table zzx_order_position AUTO_INCREMENT = {$max_oid}";
    mysqli_query($my_conn, $sql);

    // 验证持仓表自增键
    $sql = "select table_name, AUTO_INCREMENT from information_schema.tables where table_name='zzx_order_position' 
  and table_schema='{$config['DB_NAME']}'";
    $res = mysqli_query($my_conn, $sql);
    $res = mysqli_fetch_array($res, MYSQLI_ASSOC);
    echo "已修改持仓表自增键起始值为：{$res['AUTO_INCREMENT']}，被修改的表名：{$res['table_name']}\n";


    // 载入持仓订单
    loading_orders($my_conn);
}
